<script lang="ts" setup>
import type { ProcessDefinitionInOrUpReq, ProcessDefinitionVO, QueryProcessDefinitionReq } from '@/api/process/processDefinitionType'
import { pageProcessDefinition, publishProcessDefinition, saveProcessDefinition } from '@/api/process/processDefinitionApi'
// 引入路由
import router from '@/router'
// 引入pinia
import piniaStore from '@/store'
// 引入BPMN小仓库
import useBPMNStore from '@/store/bpmn/bpmnStore'
import useLayoutStore from '@/store/modules/setting'
import { ElMessage } from 'element-plus'
import { nextTick, onMounted, reactive, ref, watch } from 'vue'

// 使用BPMN小仓库
const bpmnStore = useBPMNStore(piniaStore)

// 使用layout组件小仓库
const layoutStore = useLayoutStore()
// 定义响应式数据 processName 收集查询条件 【流程名称】
const processName = ref('')
// 定义响应式数据 currentPage 收集当前页码
const currentPage = ref<number>(1)
// 定义响应式数据 pageSize 收集每页显示的条数
const pageSize = ref<number>(10)
// 定义响应式数据 total 收集总数据条数
const total = ref<number>(0)
// 定义响应式数据 showProcessDefinitionDrawer 控制添加流程抽屉的显示与隐藏
const showProcessDefinitionDrawer = ref<boolean>(false)
// 定义响应式数据 processDefinitionDrawerTitle 控制添加流程抽屉的标题
const processDefinitionDrawerTitle = ref<string>('')
// 定义响应式数据 operatePDFormRef 收集表单实例
const operatePDFormRef = ref()
// 定义数据 processDefinitionParams 表单参数
const processDefinitionParams = reactive<ProcessDefinitionInOrUpReq>({
  id: 0,
  processKey: '',
  processName: '',
  processVersion: 1,
  processStatus: 0,
  description: '',
  deleted: false,
})
// 定义数据 operatePDRules 表单校验规则
const operatePDRules = reactive({
  processKey: [
    // 必填校验
    { required: true, message: '请输入流程唯一标识', trigger: 'blur' },
    // 长度校验，不能超过50个字符
    { max: 50, message: '长度不能超过50个字符', trigger: 'blur' },
  ],
  processName: [
    // 必填校验
    { required: true, message: '请输入流程名称', trigger: 'blur' },
    // 长度校验，不能超过50个字符
    { max: 50, message: '长度不能超过50个字符', trigger: 'blur' },
  ],
  processVersion: [
    // 必填校验
    { required: true, message: '请输入流程版本号', trigger: 'blur' },
    // 必须是 0到9 组成的数字
    { pattern: /^\d+$/, message: '必须是0到9组成的数字', trigger: 'blur' },
  ],
})
// 定义响应式数据 processDefinitionList 收集表数据
const processDefinitionList = ref<ProcessDefinitionVO[]>([])

/**
 * onMounted 生命周期钩子函数
 *
 * 在组件挂载完成后执行以下操作：
 * 1. 初始化分页参数（当前页和每页数据条数）。
 * 2. 初始化流程名称为空字符串。
 * 3. 调用函数获取流程定义的分页数据。
 *
 * @param {Function} callback - Vue 的 onMounted 钩子函数的回调，无参数，无返回值。
 */
onMounted(() => {
  // 初始化分页参数：当前页为第一页，每页显示10条数据
  currentPage.value = 1
  pageSize.value = 10

  // 初始化流程名称为空字符串
  processName.value = ''

  // 调用函数获取流程定义的分页数据
  getProcessDefinitionPageData()
})

// 监听 currentPage 和 pageSize 的变化，防止非法值
watch([currentPage, pageSize], ([newPage, newSize]) => {
  if (newPage < 1)
    currentPage.value = 1
  if (newSize < 1 || newSize > 100)
    pageSize.value = 10
})

// 重置查询条件
function resetQuery() {
  layoutStore.refresh = !layoutStore.refresh
}

// 表格列定义
const tableColumns = [
  { label: '#', type: 'index', align: 'center', width: '50px' },
  { label: 'ID', prop: 'id', align: 'center' },
  { label: '流程名称', prop: 'processName', align: 'center' },
  { label: '流程唯一标识', prop: 'processKey', align: 'center' },
  { label: '流程版本号', prop: 'processVersion', align: 'center', target: true },
  { label: '流程状态', prop: 'processStatus', align: 'center' },
  { label: '流程描述/说明', prop: 'description', align: 'center' },
  { label: '创建时间', prop: 'createTime', align: 'center' },
  { label: '创建人', prop: 'creatorName', align: 'center' },
  { label: '修改时间', prop: 'modifyTime', align: 'center' },
  { label: '修改人', prop: 'modifierName', align: 'center' },
  { label: '操作', prop: 'action', align: 'center', width: '200px' },
]

/**
 * 打开添加流程的抽屉并初始化相关状态。
 *
 * @function addProcessDefinition
 * @description 该函数用于打开添加流程的抽屉，设置抽屉标题，清空流程参数对象，并清除表单校验信息。
 *              主要用于在用户点击“添加流程”时初始化界面和数据状态。
 *
 * @param {undefined} 无参数
 *
 * @returns {undefined} 无返回值
 */
function addProcessDefinition() {
  // 打开添加流程抽屉，设置其可见性为 true
  showProcessDefinitionDrawer.value = true

  // 设置抽屉标题为“添加流程”，明确当前操作的目的
  processDefinitionDrawerTitle.value = '添加流程'

  // 清空流程参数对象，确保所有字段恢复到初始状态
  Object.assign(processDefinitionParams, {
    id: null,
    processKey: '',
    processName: '',
    processVersion: 1,
    processStatus: 0,
    description: '',
    deleted: false,
  })

  // 使用 nextTick 确保 DOM 更新完成后清除表单校验信息
  nextTick(() => {
    operatePDFormRef.value.clearValidate()
  })
}

/**
 * 保存流程定义的异步函数。
 *
 * @function onSaveProcessDefinition
 * @description 该函数用于校验表单数据、保存流程定义，并根据保存结果执行相应的操作（如关闭抽屉或显示提示信息）。
 *              如果保存失败或发生异常，会向用户显示错误信息。
 *
 * @returns {Promise<void>} 无返回值，但可能抛出异常。
 */
async function onSaveProcessDefinition() {
  try {
    // 校验表单数据，确保用户输入符合要求
    await operatePDFormRef.value.validate()

    // 调用接口保存流程定义数据
    const result: any = await saveProcessDefinition(processDefinitionParams)

    // 判断保存结果是否成功
    if (result.success && result.code === 200) {
      // 如果保存成功，关闭抽屉并提示用户操作成功
      showProcessDefinitionDrawer.value = false
      ElMessage({
        message: '操作成功',
        type: 'success',
      })
    }
    else {
      // 如果保存失败，提示用户具体的错误信息
      ElMessage({
        message: result.message,
        type: 'error',
      })
    }
  }
  catch (error) {
    // 捕获异常并处理错误信息
    let errorMessage = '未知错误'
    if (error instanceof Error) {
      errorMessage = error.message
    }
    else {
      errorMessage = '表单校验失败'
    }
    ElMessage({
      message: `保存失败: ${errorMessage}`,
      type: 'error',
    })
  }
}

/**
 * 获取流程定义的分页数据。
 *
 * @function getProcessDefinitionPageData
 * @description 该函数用于组装分页查询参数，调用分页查询接口，并根据查询结果更新流程列表或提示错误信息。
 *              如果查询失败或发生异常，会通过 ElMessage 提示用户错误信息。
 *
 * @returns {Promise<void>} 无返回值，异步操作完成后更新相关状态或显示错误提示。
 */
async function getProcessDefinitionPageData() {
  try {
    // 组装分页查询参数，包含流程名称和分页信息
    const queryParams: QueryProcessDefinitionReq = {
      processName: processName.value,
      pageReq: {
        current: currentPage.value,
        size: pageSize.value,
      },
    }

    // 调用分页查询接口，获取流程定义数据
    const result: any = await pageProcessDefinition(queryParams)

    // 判断查询结果是否成功，成功则更新流程列表和总记录数
    if (result.success && result.code === 200) {
      processDefinitionList.value = result.data

      // 字典 processStatusMap 的定义
      const processStatusMap: { [key: string]: string } = {
        0: '草稿',
        1: '发布',
        2: '停用',
      }

      // 将 processDefinitionList.value 中的 processStatus 根据0-草稿, 1-发布, 2-停用翻译，如果都没有则显示未知
      processDefinitionList.value.forEach((item: any) => {
        item.processStatus = processStatusMap[item.processStatus] || '未知'
      })
      total.value = result.total
    }
    else {
      // 查询失败时，提示用户错误信息
      ElMessage({
        message: result.message,
        type: 'error',
      })
    }
  }
  catch (error) {
    // 捕获异常并提取错误信息
    let errorMessage = '未知错误'
    if (error instanceof Error) {
      errorMessage = error.message
    }

    // 显示异常错误消息
    ElMessage({
      message: `查询失败: ${errorMessage || '未知错误'}`,
      type: 'error',
    })
  }
}

/**
 * 处理页面数据的函数。
 * 该函数调用获取流程定义页面数据的方法。
 *
 * @function handerPageData
 */
function handerPageData() {
  // 调用获取流程定义页面数据的函数
  getProcessDefinitionPageData()
}

/**
 * 设计流程定义函数。
 *
 * @param {ProcessDefinitionVO} row - 流程定义的对象，包含流程的相关信息，例如 id。
 * @returns {void} 无返回值。
 */
function designProcessDefinition(row: ProcessDefinitionVO) {
  // 清空BPMN 小仓库中的 processID
  bpmnStore.processKey = ''

  // 将 row 中的 processKey 赋值给 BPMN 小仓库中的 processKey
  bpmnStore.processKey = row.processKey

  // 路由跳转到流程设计页面
  pathRoute('/process/design')
}

/**
 * 根据路径跳转路由
 * @param path 路由路径
 */
function pathRoute(path: string) {
  router.push({ path })
}

/**
 * 发布流程定义的异步函数。
 *
 * @param {ProcessDefinitionVO} row - 包含流程定义信息的对象，需提供 processKey 和 processVersion 属性。
 * @returns {Promise<void>} - 无返回值，函数主要通过调用接口和更新状态来完成操作。
 */
async function onPublishProcessDefinition(row: ProcessDefinitionVO) {
  try {
    // 调用发布流程定义的接口，并传递流程键和版本信息
    const result: any = await publishProcessDefinition({
      processKey: row.processKey,
      processVersion: row.processVersion,
    })

    // 根据接口返回的结果判断发布是否成功，并执行相应操作
    if (result.success && result.code === 200) {
      // 如果发布成功，提示用户操作成功
      ElMessage({
        message: '发布成功',
        type: 'success',
      })

      // 初始化分页参数为默认值：当前页为第一页，每页显示10条数据
      currentPage.value = 1
      pageSize.value = 10

      // 清空流程名称的输入框内容
      processName.value = ''

      // 重新获取流程定义数据以刷新页面
      getProcessDefinitionPageData()
    }
    else {
      // 如果发布失败，提示用户具体的错误信息
      ElMessage({
        message: result.message,
      })
    }
  }
  catch (error) {
    // 捕获异常并提取错误信息，确保提供有意义的错误提示
    let errorMessage = '未知错误'
    if (error instanceof Error) {
      errorMessage = error.message
    }

    // 显示异常错误消息，提示用户发布失败的具体原因
    ElMessage({
      message: `发布失败: ${errorMessage || '未知错误'}`,
      type: 'error',
    })
  }
}
</script>

<template>
  <!-- 查询条件区域 -->
  <el-card style="height: 75px;">
    <el-form :inline="true" class="form-inline">
      <el-form-item label="流程名称">
        <el-input
          v-model.trim="processName"
          placeholder="请输入流程名称"
          maxlength="50"
          show-word-limit
        />
      </el-form-item>
      <el-form-item>
        <el-button v-hasButton="`btn.definition.page`" type="primary" icon="Search" @click="getProcessDefinitionPageData">
          查询
        </el-button>
        <el-button icon="Refresh" @click="resetQuery">
          重置
        </el-button>
      </el-form-item>
    </el-form>
  </el-card>

  <!-- 查询结果列表区域 -->
  <el-card style="margin: 10px 0px;">
    <el-button v-hasButton="`btn.definition.save`" type="primary" icon="Plus" @click="addProcessDefinition">
      添加流程
    </el-button>
    <el-table style="margin: 10px 0px;" :border="true" :data="processDefinitionList">
      <!-- ID 区域 -->
      <el-table-column type="selection" align="center" width="50px" />
      <!-- 表格数据 区域 -->
      <el-table-column
        v-for="(column, index) in tableColumns"
        :key="index"
        :type="column.type"
        :label="column.label"
        :prop="column.prop"
        :align="column.align"
        :width="column.width"
      >
        <!-- 使用单个 template 包裹所有条件 -->
        <template #default="scope">
          <!-- 判断是否需要Tag显示 processVersion 的标签 -->
          <el-tag v-if="column.target">
            {{ scope.row.processVersion }}
          </el-tag>
          <!-- 判断是否是操作列 -->
          <div v-else-if="column.label === '操作'">
            <el-button type="primary">
              修改
            </el-button>
            <!-- 跳转到设计界面 -->
            <el-button type="success" @click="designProcessDefinition(scope.row)">
              设计
            </el-button>
            <!-- 发布流程功能按钮 -->
            <el-button type="primary" @click="onPublishProcessDefinition(scope.row)">
              发布
            </el-button>
          </div>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页器 -->
    <el-pagination
      v-model:current-page="currentPage"
      v-model:page-size="pageSize"
      :page-sizes="[10, 20, 30, 40, 50]"
      layout="prev, pager, next, jumper,->, sizes, total"
      :total="Math.max(total, 0)"
      @current-change="getProcessDefinitionPageData"
      @size-change="handerPageData"
    />
  </el-card>

  <!-- 添加流程抽屉 -->
  <el-drawer v-model="showProcessDefinitionDrawer">
    <!-- 抽屉标题区域 -->
    <template #header>
      <h4>{{ processDefinitionDrawerTitle }}</h4>
    </template>
    <!-- 抽屉表单区域 -->
    <template #default>
      <el-form ref="operatePDFormRef" :model="processDefinitionParams" :rules="operatePDRules">
        <el-form-item label="流程唯一标识" prop="processKey">
          <el-input v-model="processDefinitionParams.processKey" placeholder="请输入流程唯一标识" />
        </el-form-item>
        <el-form-item label="流程名称" prop="processName">
          <el-input v-model="processDefinitionParams.processName" placeholder="请输入流程名称" />
        </el-form-item>
        <el-form-item label="流程版本号" prop="processVersion">
          <el-input v-model="processDefinitionParams.processVersion" placeholder="请输入流程版本号" />
        </el-form-item>
        <el-form-item label="流程状态" prop="processStatus">
          <el-select v-model="processDefinitionParams.processStatus" placeholder="请选择流程状态">
            <el-option label="草稿" :value="0" />
            <el-option label="发布" :value="1" />
            <el-option label="停用" :value="2" />
          </el-select>
        </el-form-item>
        <el-form-item label="流程描述/说明" prop="description">
          <el-input v-model="processDefinitionParams.description" placeholder="请输入流程描述/说明" />
        </el-form-item>
        <el-form-item label="是否删除" prop="deleted">
          <el-switch v-model="processDefinitionParams.deleted" active-text="是" inactive-text="否" />
        </el-form-item>
      </el-form>
    </template>
    <!-- 抽屉底层 按钮 区域 -->
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="showProcessDefinitionDrawer = false">
          取消
        </el-button>
        <el-button v-hasButton="`btn.definition.save`" type="primary" @click="onSaveProcessDefinition">
          确定
        </el-button>
      </div>
    </template>
  </el-drawer>
</template>

<style scoped>
.form-inline {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap; /* 适配小屏幕 */
}
</style>
